const express = require('express'); //express 4
const app = express();
const bodyParser = require('body-parser');
const multer = require('multer');
const upload = multer();
const cookieParser = require('cookie-parser')

app.use(cookieParser());
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded

//模拟会话 这里偷下懒啊
const Sessions = {};
//模拟数据库中用户数据
const Users = [
    { id: "01", name: "root", rname: "超级管理员", pwd: "root", mail: "cjgly@233.com", age: "28" },
    { id: "02", name: "admin", rname: "管理员", pwd: "admin", mail: "gly@233.com", age: "27" },
    { id: "03", name: "test1", rname: "测试1", pwd: "test1", mail: "cs1@233.com", age: "18" },
    { id: "04", name: "test2", rname: "测试2", pwd: "test2", mail: "cs2@233.com", age: "18" },
];
//模拟授权应用列表
const ClientApps = [
    {
        //客户ID
        client_id: "1881139527",
        //应用名称
        client_name: "测试应用2",
        //应用网站
        home_url: "http://app2.com:8082",
        //描述
        info: "一些自定义信息(比如APP2)",
        //创建时间
        creation_date: "2019-3-29",
        //认证密钥
        authorization: '623098a7c4018ae2f840b0d8763fb61732f1f7ce'
    }
];
//首页
app.get('/', function (req, res) {
    let sid = req.cookies.session_id;
    let s = Sessions[sid];
    if (sid && s) {
        //用户登陆显示用户信息 
        let user = s.user;
        return res.send(`<html> 
            <head>
            <meta charset="UTF-8">
            </head>
            <body>
            <h3>Hello ${user.name}</h3><a href="/login">退出登陆</a>
            </body>
            </html>`);
    }
    //用户未登录则重定向
    return res.redirect('/login');
});
//登陆
app.get('/login', function (req, res) {
    let sid = req.cookies.session_id;
    if (sid) {
        //清除会话与coockie 
        if (Sessions[sid]) delete Sessions[sid];
        res.clearCookie('session_id', { domain: '.app1.com' });
    }
    res.write(`<html> 
    <head>
    <meta charset="UTF-8">
    </head>
    <body> <h1>APP1:授权服务-登录</h1>
        <form action="/onlogin" method="post">
            用户名: <input name="name" type="text" /><br />
            密码: <input name="pwd" type="password" />
            <input value="提交" type="submit" />
        </form>
    </body>
    </html>`);
    res.send();
});
//提交登陆
app.post('/onLogin', upload.array(), function (req, res) {
    let name = req.body.name;
    let pwd = req.body.pwd;
    if (name && pwd) {
        let user = Users.find(u => name == u.name && pwd == u.pwd);
        if (user) {
            //创建登陆会话
            let sid = Buffer.from(user.name + "_" + (+ new Date())).toString("base64");
            Sessions[sid] = { user: Object.assign({}, user, { pwd: "", id: "" }) };
            // res.cookie('session_id', sid);
            res.cookie('session_id', sid, { domain: '.app1.com' });
            return res.send(`正在跳转....<script>setTimeout(function(){location.href="/";},2000);</script>`);
        }
    }
    res.send(`<html> 
    <head>
    <meta charset="UTF-8">
    </head>
    <body> 登陆失败<br/><a href="/">返回首页</a></body>
    </html>`);
});
//授权页面
app.get('/oauth2/authorize', function (req, res) {
    let sid = req.cookies.session_id;
    let client_id = req.param('client_id');
    if (sid && client_id) {
        let s = Sessions[sid];
        if (s && s.user) {
            for (let app of ClientApps) {
                if (app.client_id == client_id) {
                    s.flag = (+new Date() - 200000000000).toString(); //生成请求标识示例
                    //显示授权页面
                    res.write(`<html> 
                    <head>
                    <meta charset="UTF-8">
                    </head> <h1>APP1:授权请求</h1>  
                        <h4>发起应用:${app.client_name}</h4>
                        <h4>应用网址:<a href="${app.home_url}">${app.home_url}</a></h4>
                        <h4>描述:${app.info}</h4> 
                        <form action="" method="post">
                            <input value="${s.flag}" name="flag" hidden style="display: none;" />
                            <input value="授权" type="submit" />
                        </form>
                        <script>document.querySelector("form").action=location.href;</script></body>
                        </html>`);
                    res.send();
                    return;
                }
            }
        }
    }
    //重定向到登陆
    return res.redirect('/login');
});
//授权请求
app.post('/oauth2/authorize', upload.array(), function (req, res) {
    let sid = req.cookies.session_id;
    let s = Sessions[sid];
    if (!sid || !s || !req.body || !req.body.flag || req.body.flag != s.flag) return res.redirect('/login');
    // let scope = request.query.scope;//表示申请的权限范围，可选项
    let client_id = req.param('client_id');//表示客户端的ID，必选项
    let redirect_uri = req.param('redirect_uri');//表示重定向URI，可选项
    let response_type = req.param('response_type');//表示授权类型，必选项，此处的值固定为"code"
    let state = req.param('state');//表示客户端的当前状态，可以指定任意值，认证服务器会原封不动地返回这个值。
    if (client_id && redirect_uri && response_type == "code" && s.user) {
        for (let app of ClientApps) {
            if (app.client_id == client_id) {
                //记录
                Sessions[sid].client_id = client_id;
                Sessions[sid][client_id] = Object.assign({}, app);
                Sessions[sid][client_id].redirect_uri = redirect_uri;
                Sessions[sid][client_id].grant_type = "authorization_code";
                let code = Sessions[sid][client_id].code = (+new Date() - 100000000000).toString(); //生成code 你可以用随机数啥的
                return res.redirect(`${redirect_uri}?code=${code}&state=${state}`);
            }
        }
    }
    //这里重定向到登陆，可以自行根据实际情况做处理
    return res.redirect('/login');
});
app.post('/oauth2/token', upload.array(), function (req, res) {
    let grant_type = req.param('grant_type');//表示使用的授权模式，必选项，此处的值固定为"authorization_code"
    let code = req.param('code');//表示上一步获得的授权码，必选项
    let redirect_uri = req.param('redirect_uri');//表示重定向URI，必选项，且必须与A步骤中的该参数值保持一致
    let client_id = req.param('client_id');//表示客户端ID，必选项
    let s, sid;
    for (let k in Sessions) {
        s = Sessions[k];
        if (s.client_id == client_id) sid = k;
    }
    if (!sid) return res.json({ "access_token": null });
    let authorization = req.headers.authorization;
    s = Sessions[sid];
    if (!s) return res.json({ "access_token": null });
    let c = s[client_id];
    if (c && c.grant_type == grant_type && c.code == code && c.redirect_uri == redirect_uri && c.authorization == authorization) {
        if (!s.tokens) s.tokens = {};
        let resBody = {
            "access_token": sid,//表示访问令牌，必选项 ，我这里就直接用sessionID来模拟token
            "token_type": "Bearer",//表示令牌类型，该值大小写不敏感，必选项，可以是bearer类型或mac类型。
            "expires_in": 3600,//表示过期时间，单位为秒。如果省略该参数，必须其他方式设置过期时间
            "refresh_token": null,//表示更新令牌，用来获取下一次的访问令牌，可选项
            "scope": null//scope：表示权限范围，如果与客户端申请的范围一致，此项可省略
        };
        s.tokens[sid] = Object.assign({ timestamp: (+new Date()) }, resBody);
        return res.json(resBody);
    }
    return res.json({ "access_token": null });
});
//验证是否到期
function tokenIsExpires(token, session) {
    //自行修改以下代码 来模拟到期的情况
    let tokenInfo = session.tokens[token];
    if (!token) return true;
    let nowTimestamp = (+new Date());
    let tokenTimestamp = tokenInfo.timestamp;
    let y = (nowTimestamp - tokenTimestamp) > (tokenInfo.expires_in * 1000);
    if (y) delete session.tokens[token];
    return y
}
//模拟获取用户信息
app.post('/user/getuserinfo', upload.array(), function (req, res) {
    let token = req.param('access_token');//表示客户端的ID，必选项
    if (token) {
        if (!tokenIsExpires(token, Sessions[token])) {
            let user = Object.assign({}, Sessions[token].user, { pwd: "", id: "" });
            if (user) return res.json({ "error": null, "success": true, "data": user });
        }
    }
    res.json({ "error": "授权验证失败", "success": false });
});
app.listen(8081);